package gui.frames;

import gui.interfaces.ValidatorInterface;
import gui.utils.ComponentUtils;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Properties;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;

import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import common.utils.CommonUtils;

public class SetupFrame extends JFrame implements ValidatorInterface {

	private static final long serialVersionUID = 1L;
	private static final int MIN_CONNECTIONS = 4;
	private static final int MAX_CONNECTIONS = 20;
	private static final String EMPTY_STRING = "";
	
	private JTextField usernameField;
	private JTextField passwordField;
	private JTextField urlField;
	private JTextField driverField;
	private JSpinner connectionsSpinner;
	private JButton applyButton;
	private JButton revertButton;
	private JButton cancelButton;
	private final Properties properties;
	private final AbstractAction applyAction;

    public SetupFrame(Properties properties, AbstractAction applyAction) {
        this.properties = properties;
		this.applyAction = applyAction;
        buildFrame();
        installListeners();
        initFill();
    }

	private void buildFrame() {
		setTitle("Setup");
        setSize(new Dimension(400, 380));
        setResizable(false);
        ComponentUtils.centerOnScreen(this);
        
        String columnConstraints = "p,3dlu,133dlu";
        String rowConstraints = "p,3dlu,p,3dlu,p,3dlu,p,10dlu,p,3dlu,p,3dlu,p";
		FormLayout layout = new FormLayout(columnConstraints, rowConstraints);
		
		JPanel fieldsPanel = new JPanel();
		PanelBuilder fieldsPanelBuilder = new PanelBuilder(layout, fieldsPanel);
		fieldsPanelBuilder.setDefaultDialogBorder();
		CellConstraints cc = new CellConstraints();
		
		usernameField = new JTextField();
		passwordField = new JTextField();
		urlField = new JTextField();
		driverField = new JTextField();
		
		connectionsSpinner = new JSpinner();
		SpinnerNumberModel numberModel = new SpinnerNumberModel(10, MIN_CONNECTIONS, MAX_CONNECTIONS, 1);
		connectionsSpinner.setModel(numberModel);
		JTextField editor = ((JSpinner.DefaultEditor)connectionsSpinner.getEditor()).getTextField();
		editor.setEditable(false);
		
		JLabel usernameLabel = new JLabel("Username:");
		JLabel passwordLabel = new JLabel("Password:");
		JLabel urlLabel = new JLabel("URL:");
		JLabel driverLabel = new JLabel("Driver:");
		JLabel connectionsLabel = new JLabel("Number of connections:");
		
		fieldsPanelBuilder.addSeparator("Database connection properties", cc.xyw(1, 1, 3));
		fieldsPanelBuilder.add(usernameLabel, cc.xy(1,3));
		fieldsPanelBuilder.add(usernameField, cc.xy(3,3));
		fieldsPanelBuilder.add(passwordLabel, cc.xy(1,5));
		fieldsPanelBuilder.add(passwordField, cc.xy(3,5));
		fieldsPanelBuilder.add(urlLabel, cc.xy(1,7));
		fieldsPanelBuilder.add(urlField, cc.xy(3,7));
		fieldsPanelBuilder.addSeparator("Database engine properties", cc.xyw(1, 9, 3));
		fieldsPanelBuilder.add(driverLabel, cc.xy(1,11));
		fieldsPanelBuilder.add(driverField, cc.xy(3,11));
		fieldsPanelBuilder.add(connectionsLabel, cc.xy(1,13));
		fieldsPanelBuilder.add(connectionsSpinner, cc.xy(3,13));	
		
		setLayout(new BorderLayout());
		add(createLogoPanel(), BorderLayout.NORTH);    
		add(fieldsPanel, BorderLayout.CENTER);    
		add(createButtonsPanel(), BorderLayout.SOUTH);
	}
	
	private JPanel createLogoPanel() {
		JPanel panel = new JPanel();
        JLabel logo = new JLabel(ComponentUtils.readScaledImageIcon("setup_logo.png",210,60));
        panel.add(logo);
        return panel;
	}
	
	private JPanel createButtonsPanel() {
		JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 5));
		applyButton = ComponentUtils.createButton("Apply");	
		revertButton = ComponentUtils.createButton("Default");	
		cancelButton = ComponentUtils.createButton("Cancel");
	
		panel.add(cancelButton);
		panel.add(revertButton);
		panel.add(applyButton);
		
		return panel;
	}
	
	private void installListeners() {
    	setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    	addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent evt)
			{
				cancel();
			}
		});
    	
		applyButton.addActionListener(new ActionListener() {		
			@Override
			public void actionPerformed(ActionEvent arg0) {
				apply();		
			}
		});
		
		revertButton.addActionListener(new ActionListener() {			
			@Override
			public void actionPerformed(ActionEvent arg0) {
				revert();		
			}
		});
		
		cancelButton.addActionListener(new ActionListener() {			
			@Override
			public void actionPerformed(ActionEvent arg0) {
				cancel();		
			}
		});	
		
		ComponentUtils.installValidator(usernameField, this);
		ComponentUtils.installValidator(urlField, this);
		ComponentUtils.installValidator(driverField, this);
	}	

	private void apply() {
		properties.setProperty(SetupPropertiesEnum.USERNAME.getPropertyKey(), usernameField.getText());
		properties.setProperty(SetupPropertiesEnum.PASSWORD.getPropertyKey(), passwordField.getText());
		properties.setProperty(SetupPropertiesEnum.URL.getPropertyKey(), urlField.getText());
		properties.setProperty(SetupPropertiesEnum.DRIVER.getPropertyKey(), driverField.getText());
		SpinnerNumberModel model = (SpinnerNumberModel) connectionsSpinner.getModel();	
		properties.setProperty(SetupPropertiesEnum.CONNECTIONS.getPropertyKey(), model.getNumber().toString());
		
		setVisible(false);
		applyAction.actionPerformed(null);
		dispose();
		System.exit(0);
	}

	private void revert() {
		usernameField.setText(SetupPropertiesEnum.USERNAME.getDefaultValue());
		passwordField.setText(SetupPropertiesEnum.PASSWORD.getDefaultValue());
		urlField.setText(SetupPropertiesEnum.URL.getDefaultValue());
		driverField.setText(SetupPropertiesEnum.DRIVER.getDefaultValue());
		connectionsSpinner.setValue(Integer.parseInt(SetupPropertiesEnum.CONNECTIONS.getDefaultValue()));
	}
	
	private void cancel() {
		dispose();
		System.exit(0);
	}
	
	@Override
	public void validate(String value) {
		boolean isValid = true;
		isValid = isValid && !CommonUtils.isEmpty(usernameField.getText());
		isValid = isValid && !CommonUtils.isEmpty(urlField.getText());
		isValid = isValid && !CommonUtils.isEmpty(driverField.getText());
		applyButton.setEnabled(isValid);	
	}
	

	private void initFill() {
		String username = (String) properties.get(SetupPropertiesEnum.USERNAME.getPropertyKey());
		String password = (String) properties.get(SetupPropertiesEnum.PASSWORD.getPropertyKey());
		String url = (String) properties.get(SetupPropertiesEnum.URL.getPropertyKey());
		String driver = (String) properties.get(SetupPropertiesEnum.DRIVER.getPropertyKey());
		String connections = (String) properties.get(SetupPropertiesEnum.CONNECTIONS.getPropertyKey());
		
		usernameField.setText(CommonUtils.isEmpty(username) ? EMPTY_STRING : username);
		passwordField.setText(CommonUtils.isEmpty(password) ? EMPTY_STRING : password);
		urlField.setText(CommonUtils.isEmpty(url) ? EMPTY_STRING : url);
		driverField.setText(CommonUtils.isEmpty(driver) ? EMPTY_STRING : driver);
		if (!CommonUtils.isEmpty(connections)) {
			connectionsSpinner.setValue(Integer.parseInt(connections));
		}
		
        validate(null);
	}
	
	enum SetupPropertiesEnum {
		USERNAME("db_username","DbMysql12"),
		PASSWORD("db_password","AkinatorPass"),
		URL("db_url","jdbc:mysql://mysqlsrv.cs.tau.ac.il:3306/DbMysql12"),
		DRIVER("jdbc_driver","com.mysql.jdbc.Driver"),
		CONNECTIONS("db_number_of_connections","10");
		
		private final String propertyKey;
		private final String defaultValue;

		SetupPropertiesEnum(String propertyKey, String defaultValue) {
			this.propertyKey = propertyKey;
			this.defaultValue = defaultValue;	
		}

		public String getDefaultValue() {
			return defaultValue;
		}

		public String getPropertyKey() {
			return propertyKey;
		}
	}

}
